// exception.cc 
//	Entry point into the Nachos kernel from user programs.
//	There are two kinds of things that can cause control to
//	transfer back to here from user code:
//
//	syscall -- The user code explicitly requests to call a procedure
//	in the Nachos kernel.  Right now, the only function we support is
//	"Halt".
//
//	exceptions -- The user code does something that the CPU can't handle.
//	For instance, accessing memory that doesn't exist, arithmetic errors,
//	etc.  
//
//	Interrupts (which can also cause control to transfer from user
//	code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "stdio.h"
#include "copyright.h"
#include "main.h"
#include "synchconsole.h"
#include "syscall.h"
#include "ksyscall.h"

#define  ARGV_LEN  20

//----------------------------------------------------------------------
// ExceptionHandler
// 	Entry point into the Nachos kernel.  Called when a user program
//	is executing, and either does a syscall, or generates an addressing
//	or arithmetic exception.
//
// 	For system calls, the following is the calling convention:
//
// 	system call code -- r2
//		arg1 -- r4
//		arg2 -- r5
//		arg3 -- r6
//		arg4 -- r7
//
//	The result of the system call, if any, must be put back into r2. 
//
// If you are handling a system call, don't forget to increment the pc
// before returning. (Or else you'll loop making the same system call forever!)
//
//	"which" is the kind of exception.  The list of possible exceptions 
//	is in machine.h.
//----------------------------------------------------------------------

void
ExceptionHandler(ExceptionType which)
{
    int type = kernel->machine->ReadRegister(2);

    DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");

    switch (which) {
    case SyscallException:
      switch(type) {
      case SC_Halt:
	DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
	// printf("halt here!\n");

	SysHalt();

	ASSERTNOTREACHED();
	break;

      case SC_Add:
	DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
	
	/* Process SysAdd Systemcall*/
	int result;
	result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4),
			/* int op2 */(int)kernel->machine->ReadRegister(5));
	printf("add :%d\n", result);  /* add by lihaitao, 20110314, printf the adding result */

	DEBUG(dbgSys, "Add returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
	  
/* begin, add by lihaitao, 20110314 */
	   case SC_Print:
	DEBUG(dbgSys, "Print " << kernel->machine->ReadRegister(4) << "\n");
	/* Process SysAdd Systemcall*/
	//printf("test printf!\n");
/*	char ch;
	int addr;
	addr = (int)kernel->machine->ReadRegister(4);
	do {
		kernel->machine->ReadMem(addr++, 1, (int *)&ch);
		kernel->synchConsoleOut->PutChar(ch);
		//printf("%c", ch);
	} while (ch != '\0');
*/
	SysPrint((char *)kernel->machine->ReadRegister(4));

	DEBUG(dbgSys, "Print returning!\n");
	/* Prepare Result */
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;

/* end, add by lihaitao, 20110314 */

/* begin, add by lihaitao, 20110319 */
	   case SC_PrintNum:
	DEBUG(dbgSys, "PrintNum " << kernel->machine->ReadRegister(4) << "\n");
	/* Process SysAdd Systemcall*/
/*	int num;
	int i;
	i = 0;
	char cnum[16];
	num = (int)kernel->machine->ReadRegister(4);
//	printf("%d", num);
	sprintf(cnum, "%d", num);
	do{
		kernel->synchConsoleOut->PutChar(cnum[i++]);
	}while(cnum[i] != '\0');
*/
	SysPrintNum((int)kernel->machine->ReadRegister(4));

	DEBUG(dbgSys, "Print returning!\n");
	/* Prepare Result */
	// kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;

/* end, add by lihaitao, 20110319 */

/* begin, add by lihaitao, 20110402 */
	case SC_Exec:
	{
		DEBUG(dbgSys, "Exec " << kernel->machine->ReadRegister(4) << "\n");
		/* Process SysAdd Systemcall*/
	//	printf("\nExpected Exec exception %d %d\n", which, type);
		
	    int paraddr;
		paraddr = kernel->machine->ReadRegister(4); 
	//    printf("Parameter address is %d\n", paraddr);
	    char fn[40];
	    for(int i=0;i<10;i++){
	//		printf("@@try to read %d\n",paraddr+4*i);
	        kernel->machine->ReadMem(paraddr+4*i, 4, (int *)(fn+4*i));
	    }
	//	printf("Exec file is %s\n",fn); 
		/* Modify return point */
	IncrePC();
    StartProcess(fn);

	return;
	
	ASSERTNOTREACHED();

	break;
	}
/* end, add by lihaitao, 20110402 */

/* begin, add by lihaitao, 20110408 */
	case SC_Exit:
	{
	//	DEBUG(dbgSys, "Exit " << kernel->machine->ReadRegister(4) << "\n");
		/* Process SysAdd Systemcall*/
		AddrSpace *prespace,*space;
		prespace = kernel->spaceList->RemoveFront();
		delete prespace;
		if (kernel->spaceList->IsEmpty())
		{
		  DEBUG(dbgSys,"kernel->spaceList is empty!\n");
		  SysHalt();
		}
		space = kernel->spaceList->Front();
		kernel->currentThread->space = space;

		space->RestoreState();
		space->RestoreReg();
//		space->Print();
		kernel->machine->Run();

		return;
		
		ASSERTNOTREACHED();

		break;
	}
/* end, add by lihaitao, 20110408 */

/* begin, add by lihaitao, 20110418 */
      case SC_Read:
	  		{
	DEBUG(dbgSys, "Read " << kernel->machine->ReadRegister(4) << " + "  
						  << kernel->machine->ReadRegister(5) << " + "
						  << kernel->machine->ReadRegister(6) << "\n");
	
	/* Process SysRead Systemcall*/
	int result;
	result = SysRead(/* op1 */(char *)kernel->machine->ReadRegister(4),
					 /* op2 */(int)kernel->machine->ReadRegister(5),
					 /* op3 */(int)kernel->machine->ReadRegister(6));

	DEBUG(dbgSys, "Read returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

/* end,   add by lihaitao, 20110418 */

/* begin, add by lihaitao, 20110418 */
      case SC_Write:
	  		{
	DEBUG(dbgSys, "Write " << kernel->machine->ReadRegister(4) << " + "  
	 					   << kernel->machine->ReadRegister(5) << " + "
						   << kernel->machine->ReadRegister(6) << "\n");
	
	/* Process SysWrite Systemcall*/
	int result;
	result = SysWrite(/* op1 */(char *)kernel->machine->ReadRegister(4),
					 /* op2 */(int)kernel->machine->ReadRegister(5),
					 /* op3 */(int)kernel->machine->ReadRegister(6));

	DEBUG(dbgSys, "Write returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

/* end,   add by lihaitao, 20110418 */

		case SC_Copy:
	  		{
	DEBUG(dbgSys, "Copy " << kernel->machine->ReadRegister(4) << " + " 
						     << kernel->machine->ReadRegister(5) << "\n");
	
	/* Process SysWrite Systemcall*/
	int result;
	char file1[ARGV_LEN], file2[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), file1);
	SysGetchar((char *)kernel->machine->ReadRegister(5), file2);
	result = SysCopy(file1, file2);

	DEBUG(dbgSys, "Copy returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Rename:
	  		{
	DEBUG(dbgSys, "Rename " << kernel->machine->ReadRegister(4) << " + " 
						     << kernel->machine->ReadRegister(5) << "\n");
	
	/* Process SysWrite Systemcall*/
	int result;
	char file1[ARGV_LEN], file2[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), file1);
	SysGetchar((char *)kernel->machine->ReadRegister(5), file2);
	result = SysRename(file1, file2);

	DEBUG(dbgSys, "Rename returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Append:
	  		{
	DEBUG(dbgSys, "Append " << kernel->machine->ReadRegister(4) << " + " 
						    << kernel->machine->ReadRegister(5) << "\n");
	
	/* Process SysWrite Systemcall*/
	int result;
	char file1[ARGV_LEN], file2[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), file1);
	SysGetchar((char *)kernel->machine->ReadRegister(5), file2);	
	result = SysAppend(file1, file2);

	DEBUG(dbgSys, "Append returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Echo:
	  		{
	DEBUG(dbgSys, "Echo " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysWrite Systemcall*/
	char comment[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), comment);
	SysEcho(comment);

	DEBUG(dbgSys, "Echo returning with " << result << "\n");
	/* Prepare Result */
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Create:
	  		{
	DEBUG(dbgSys, "Create " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysCreate Systemcall*/
	int result;
	char file[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), file);
	result = SysCreate(file);

	DEBUG(dbgSys, "Create returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Move:
	  		{
	DEBUG(dbgSys, "Move " << kernel->machine->ReadRegister(4) << " + " 
						  << kernel->machine->ReadRegister(5) << "\n");
	
	/* Process SysMove Systemcall*/
	int result;
	char path1[ARGV_LEN], path2[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), path1);
	SysGetchar((char *)kernel->machine->ReadRegister(5), path2);	
	result = SysMove(path1, path2);

	DEBUG(dbgSys, "Move returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Remove:
	  		{
	DEBUG(dbgSys, "Remove " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysRemove Systemcall*/
	int result;
	char name[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), name);
	result = SysRemove(name);

	DEBUG(dbgSys, "Remove returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Mkdir:
	  		{
	DEBUG(dbgSys, "Mkdir " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysMkdir Systemcall*/
	int result;
	char name[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), name);
	result = SysMkdir(name);

	DEBUG(dbgSys, "Mkdir returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Rmdir:
	  		{
	DEBUG(dbgSys, "Rmdir " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysRmdir Systemcall*/
	int result;
	char name[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), name);
	result = SysRmdir(name);

	DEBUG(dbgSys, "Rmdir returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Changedir:
	  		{
	DEBUG(dbgSys, "Changedir " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysChangedir Systemcall*/
	int result;
	char name[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), name);
	result = SysChangedir(name);

	DEBUG(dbgSys, "Changedir returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Listdir:
	  		{
	DEBUG(dbgSys, "Listdir " << kernel->machine->ReadRegister(4) << "\n");
	
	/* Process SysListdir Systemcall*/
	int result;
	char name[ARGV_LEN];
	SysGetchar((char *)kernel->machine->ReadRegister(4), name);
	result = SysListdir(name);

	DEBUG(dbgSys, "Listdir returning with " << result << "\n");
	/* Prepare Result */
	kernel->machine->WriteRegister(2, (int)result);
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

		case SC_Pwd:
	  		{
	DEBUG(dbgSys, "Pwd " << "\n");
	
	/* Process SysPwd Systemcall*/
	SysPwd();

	DEBUG(dbgSys, "Pwd returning" << "\n");
	/* Prepare Result */
	
	/* Modify return point */
	IncrePC();
	return;
	
	ASSERTNOTREACHED();

	break;
      	}

      default:
	cerr << "Unexpected system call " << type << "\n";
	break;
      }
      break;
    default:
      cerr << "Unexpected user mode exception" << (int)which << "\n";
      break;
    }
    ASSERTNOTREACHED();
}
